package server;


import classload.WebClassLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import pojo.Context;
import pojo.Host;
import pojo.Mapper;
import pojo.Server;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class Bootstrap {

    /**定义socket监听的端⼝号*/
    private int port =8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private Server server =new Server();
    private List<Mapper> serviceList = new ArrayList<>();

    /**
     * Minicat启动需要初始化展开的⼀些操作
     */
    public void start()throws Exception{
       // loadServlet();

        //定义一个线程池
        int corePoolSize = 10;
        int maximumPoolSize =50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );
        /*
            完成Minicat 1.0版本
            需求：浏览器请求http://localhost:8080,返回⼀个固定的字符串到⻚⾯"Hello Minicat!"
        */
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("=====>>>Minicat start on port:"+port);

        /*while (true){
            Socket socket = serverSocket.accept();
            //有了socket，接受到请求，获取输出流
            OutputStream outputStream = socket.getOutputStream();
            String data="Hello Minicat!";
            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length)+ data;
            outputStream.write(responseText.getBytes());
            socket.close();
        }*/

        /**
         * 完成Minicat 2.0版本
         * 需求：封装Request和Response对象，返回html静态资源⽂件
         */
       /* while (true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            response.outputHtml(request.getUrl());
            socket.close();
        }*/

        /**
         * 完成Minicat 3.0版本
         * 需求：可以请求动态资源（Servlet）
         */
       /* while (true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            // 封装Request对象和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            // 静态资源处理
            if (servletMap.get(request.getUrl())==null){
                response.outputHtml(request.getUrl());
            }else {
                HttpServlet httpServlet = servletMap.get(request.getUrl());
                httpServlet.service(request,response);
            }
            socket.close();
        }*/

       /*
        多线程改造（不使⽤线程池）
        */
        /*while(true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket,servletMap);
            requestProcessor.start();
        }*/

        //System.out.println("=========>>>>>>使⽤线程池进⾏多线程改造");
        /*
        多线程改造（使⽤线程池）
        */
        /*while (true){
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket,servletMap);
            threadPoolExecutor.execute(requestProcessor);
        }*/
        loadParseServlet();
        System.out.println("=========>>>>>>Minicat4.0改造");
        //loadServlet();
        while (true){
            Socket socket = serverSocket.accept();

            RequestProcessor requestProcessor = new RequestProcessor(socket,server);
            threadPoolExecutor.execute(requestProcessor);
        }

    }

   // private Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();

    /**
     * minicat3.0 使用
     * 加载解析web.xml，初始化Servlet
     */
   /* private void loadServlet() {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes= rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                //<servlet-class>server.LagouS  ervlet</servlet-class>
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();

                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }*/


    /**
     * 加载解析server.xml
     */
    public void loadParseServlet(){
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            //解析 server标签
            Element serverElement = (Element) rootElement.selectSingleNode("//server");
            // 解析 server 下的 Service 标签  server:service=1:n
            List<Element> serviceNodes = rootElement.selectNodes("//service");
            // 存储各个 Host
            Map<String, Host> hostMap = new HashMap<>();
            //遍历 service
            for(Element serviceElement:serviceNodes){
                Element engineNode = (Element) serviceElement.selectSingleNode("//Engine");
                List<Element> hostNodes = engineNode.selectNodes("//Host");
                // 存储有多少个项目
                Map<String, Context> contextMap = new HashMap<>();
                for(Element hostNode:hostNodes){
                    String hostName = hostNode.attributeValue("name");
                    String appBase = hostNode.attributeValue("appBase");

                    File file = new File(appBase);
                    if(!file.exists()||file.list()==null){
                        break;
                    }
                    String[] list = file.list();
                    //遍历子文件夹，即：实际的项目列表
                    for (String path:list){
                        //将项目封装成 context，并保存入map
                        contextMap.put(path,loadContextServlet(appBase+"/"+path));
                        // hsot:port
                        // eg: localhost:8080
                        hostMap.put(hostName + ":" + port, new Host(contextMap));
                    }

                }
                serviceList.add(new Mapper(hostMap));
            }
            server.setServiceList(serviceList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载解析实际项目里配置的 web.xml
     */
    public Context loadContextServlet(String path) throws Exception{
        String webPath=path+"/WEB-INF/classes/web.xml";
        File file = new File(webPath);
        if (!file.exists()){
            System.out.println("not found "+webPath);
            return null;
        }

        FileInputStream fileInputStream = new FileInputStream(webPath);
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(fileInputStream);
        Element rootElement = document.getRootElement();

        List<Element> servletElements = rootElement.selectNodes("//servlet");
        Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();
        for (Element servletElement:servletElements){
            //<servlet-name>lagou</servlet-name>
            Element servletNameElement = (Element) servletElement.selectSingleNode("servlet-name");
            String servletName = servletNameElement.getStringValue();
            // <servlet-class>server.LagouServlet</servlet-class>
            Element servletclassElement = (Element) servletElement.selectSingleNode("servlet-class");
            String servletclass = servletclassElement.getStringValue();

            // 根据servlet-name的值找到url-pattern
            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
            // 自定义类加载器，来加载 webapps 目录下的 class
            WebClassLoader webClassLoader = new WebClassLoader();
            Class<?> aClass = webClassLoader.findClass(path,servletclass);
            servletMap.put(urlPattern, (HttpServlet) aClass.getDeclaredConstructor().newInstance());
        }
        return new Context(servletMap);
    }

    /**
     * Minicat 的程序启动⼊⼝
     * @param args
     */
    public static void main(String[] args){
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
